��վ�ܷ�������

Streaming#6 NOIP模拟赛Day2

今天第一次打模拟赛题解啦啦啦~ ~ ~ 关键是这一次题目比较水

Streaming#6 NOIP模拟赛Day2

T1: 九九归一

题意简述

若满足 $a^x\equiv 1(mod\ n)$ 且$x=\phi (n)$ ,并不存在更小的x满足此等式

给定$n$,共$m$个数,若满足上述条件输出1,不满足输出0。

题解

事实上这题的精髓在于求phi,但由于偷懒看了之前的代码就。。。

首先因为数据水,所以直接把n因数分解一个个判断就可以。

正解可以考虑质因数分解,每次判断
$$
x^{\frac{\phi(n)}{p_i}}\equiv 1 (mod\ n)
$$
就可以,因为质因数很少,每次出去其中一个质因数之后的数就包含了其他的质因子,如果大的数都不满足,小的也不会满足,因此可以判断。

但我好像正解打挂了就放个暴力,反正是混过了的

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+110;
int n,phi[N],prime[N],fact[N],cnt,q;
bool flag[N];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void init(int m)
{
    flag[1]=1;
    phi[1]=1;
    for(int i=2;i<=m;i++)
    {
        if(!flag[i])
        {
            prime[++prime[0]]=i;
            phi[i]=i-1;
        }
         for(int j=1;j<=prime[0]&&prime[j]*i<=m;j++)
         {
             flag[i*prime[j]]=1;
             phi[i*prime[j]]=phi[i]*(prime[j]-1);
             if(i%prime[j]==0)
             {
                 phi[i*prime[j]]=phi[i]*prime[j];
                 break;
             }
         }
    }
   int x=phi[m];
   for(int i=2;i<=sqrt(x);i++)
    if(x%i==0)
      fact[++cnt]=i;
}
int ksm(int x,int y,int mod)
{
    int sum=1;
    while(y)
    {
        if(y&1)sum=sum*x%mod;
        x=x*x%mod;
        y/=2;
    }
    return sum;
}
bool check(int x)
{
    for(int i=1;i<=cnt;i++)
    {
        if(ksm(x,fact[i],n)%n==1||ksm(x,phi[n]/fact[i],n)%n==1)return 0;
    }
    return 1;
}
main()
{
    n=read();q=read();
    init(n);
    for(int i=1;i<=q;i++)
    {
        int x;
        x=read();
        if(x==1||x==0){putchar('0');continue;}
        if(ksm(x,n,n)%n==1){putchar('0');continue;}
        if(check(x))putchar('1');
        else putchar('0');
    }
    return 0;
}

T2: LCA的统计

题意简述

给一定一棵树,求出以下式子的和对mod 1e9+7
$$
\sum_{i=1}^n \sum_{j=1}^n W_i W_j W_{lca(i,j)}
$$

题解

这个题就很水,有很多中做法,有$dfs$,树形$dp$,因为我$dp$学的不好就只打了一个暴力$dfs$

很好想,先加上所有自己和自己组合的点对。

然后在每次$dfs$开始的时候先算以自己为$lca$,也就是子树的答案和。这是求x到每个$son[x]$的权值之积,再考虑求子树之间的自由组合,相当于路径拼接一下的,也是把两边的权值积乘起来就行,很好理解。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+110;
const int mod=1e9+7;
int n,m,head[N],siz[N],deep[N],top[N],fa[N],cnt,w[N],son[N];
int sum1,ans;
long long mult(long long x,long long y)//其实不用龟速乘
{
    long long sum=0;
    while(y)
    {
        if(y%2)
            sum=(sum+x)%mod;
        x=(x+x)%mod;
        y=y/2;

    }
    return sum;
} 
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node
{
    int nt,to;
}edge[N*2];
void add(int x,int y)
{
    edge[++cnt]=(node){head[x],y};head[x]=cnt;
    edge[++cnt]=(node){head[y],x};head[y]=cnt;
}
void dfs(int x,int fa1,int d)
{
    deep[x]=d;fa[x]=fa1;siz[x]=1;son[x]=w[x];
    for(int i=head[x];i;i=edge[i].nt)
    {
        int v=edge[i].to;
        if(v==fa1)continue;
        dfs(v,x,d+1);
        siz[x]+=siz[v];
        son[x]=(son[x]+son[v])%mod;
    }
}
void DFS(int x)
{
    if(siz[x]==1)return ;
    sum1=(sum1+mult(mult(w[x],w[x]),(son[x]-w[x]+mod))*2%mod)%mod;//有减号的地方一定记得+mod
    for(int i=head[x];i;i=edge[i].nt)
    {
        int v=edge[i].to;
        if(v==fa[x])continue;
        sum1=(sum1+mult(mult(w[x],(son[v])),(son[x]-son[v]-w[x]+mod))%mod)%mod;
        DFS(v);
    }
}
main()
{
    n=read();w[1]=read();ans+=mult(mult(w[1],w[1]),w[1]);
    for(int i=2;i<=n;i++)
    {
        fa[i]=read();w[i]=read();
        add(i,fa[i]);
        ans=(ans+mult(mult(w[i],w[i]),w[i]))%mod;
    }
    dfs(1,0,1);
    DFS(1);
    ans=(ans+sum1)%mod;
    printf("%lld",ans%mod);
    return 0;
}

T3: 四驱兄弟

题意简述

给定一些字符串,每个字符串对应一个点,给定一些边,求有哪些边相连之后不会出现环。、

(实际上题目描述非常难懂。。。。)

题解

实际上此题读题有些费劲,但看懂了就是一道kruskal裸题。

首先用hash或map处理一下字符串。然后按边权排序,用并查集判环。

每次加边前判定一下$findf(x)$ 是否等于$findf(y)$,就行。。。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+110;
const int INF=(1<<30);
int n,m,head[N],id,fa[N],minn=(1<<30),ans[N],cnt;
map<string,int>name;
string s,t;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node
{
    int w,u,v;
    bool operator < (const node &a)const
    {
        return w<a.w;
    }
}edge[N*2];

int findf(int x)
{
    if(x==fa[x])return x;
    else return fa[x]=findf(fa[x]);
}
void Kruskal()
{
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        int fx=findf(edge[i].u);
        int fy=findf(edge[i].v);
        if(fx==fy){continue;}
        printf("%lld\n",edge[i].w);
        fa[fx]=fy;
        cnt++;
    }
    for(int i=cnt+1;i<=m;i++)printf("INF\n");
}
main()
{
    m=read();n=read();
    for(int i=1;i<=n;i++)
    {
        edge[i].w=read();
        cin>>s>>t;
        if(!name[s])name[s]=++id;
        if(!name[t])name[t]=++id;
        edge[i].u=name[s],edge[i].v=name[t];

    }
    for(int i=1;i<=id;i++)fa[i]=i;
    sort(edge+1,edge+1+n);
    Kruskal();
    return 0;
}